home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1999 Spring
/
macformat-077.iso
/
Shareware Plus
/
Development
/
SpriteWorld 2.2
/
SpriteWorld files
/
Utils
/
Circular Scrolling.c
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1999-01-12
|
48.1 KB
|
1,631 lines
|
[
TEXT/CWIE
]
///--------------------------------------------------------------------------------------
// Circular Scrolling.c
//
// By: Vern Jensen
//
// Created: 7/20/96
//
// Description: Routines that enable you to wrap around while scrolling
//
// Implementation note: Unlike the standard scrolling engine, Sprites and the visScrollRect
// in this engine will only hang off the right and bottom edges of the offscreen area when
// wrapping, not the top and left. This was done to simplify the code in various sections.
// It could be done in the standard scrolling engine as well if we want.
//
// As for how the engine works, it first clips the visScrollRect with the circular world's
// bounds, wraps each part, and calls a function to draw the sprites in each part. This
// function clips each sprite with the circular world's bounds, and draws each part,
// clipping it to the current piece of the visScrollRect it's being drawn in. It may sound
// complex, but it's the only way to do it without running into other problems.
///--------------------------------------------------------------------------------------
#ifndef __QUICKDRAW__
#include <QuickDraw.h>
#endif
#ifndef __MEMORY__
#include <Memory.h>
#endif
#ifndef __GESTALT__
#include <Gestalt.h>
#endif
#ifndef __SPRITEWORLD__
#include "SpriteWorld.h"
#endif
#ifndef __SPRITEWORLDUTILS__
#include "SpriteWorldUtils.h"
#endif
#ifndef __BLITPIXIE__
#include "BlitPixie.h"
#endif
#ifndef __SCROLLING__
#include "Scrolling.h"
#endif
#ifndef __TILING__
#include "Tiling.h"
#endif
#ifndef __CIRCULARSCROLLING__
#include "Circular Scrolling.h"
#endif
extern SpritePtr gCurrentSpriteBeingDrawn;
///--------------------------------------------------------------------------------------
// SWUpdateCircularSpriteWorld
///--------------------------------------------------------------------------------------
SW_FUNC void SWUpdateCircularSpriteWorld(
SpriteWorldPtr spriteWorldP)
{
GWorldPtr saveGWorld;
GDHandle saveGDH;
SW_ASSERT(spriteWorldP != NULL);
SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
GetGWorld( &saveGWorld, &saveGDH );
// Copy the background into the work area
SetGWorld(spriteWorldP->workFrameP->framePort, nil);
(*spriteWorldP->offscreenDrawProc)(spriteWorldP->backFrameP,
spriteWorldP->workFrameP,
&spriteWorldP->backFrameP->frameRect,
&spriteWorldP->workFrameP->frameRect);
spriteWorldP->frameHasOccurred = true;
SWAnimateCircularSpriteWorld(spriteWorldP);
SetGWorld( saveGWorld, saveGDH );
}
///--------------------------------------------------------------------------------------
// SWProcessCircularSpriteWorld
///--------------------------------------------------------------------------------------
SW_FUNC void SWProcessCircularSpriteWorld(
SpriteWorldPtr spriteWorldP)
{
register SpriteLayerPtr curSpriteLayerP;
register SpritePtr curSpriteP;
Rect moveBounds = spriteWorldP->scrollRectMoveBounds;
// Process the sprites
SWProcessSpriteWorld(spriteWorldP);
if ( !spriteWorldP->frameHasOccurred )
{
return;
}
// Wrap any sprites that have moved outside the scrollRectMoveBounds
curSpriteLayerP = spriteWorldP->headSpriteLayerP;
while (curSpriteLayerP != NULL)
{
curSpriteP = curSpriteLayerP->headSpriteP;
while (curSpriteP != NULL)
{
// Wrap left or right
if (curSpriteP->destFrameRect.left >= moveBounds.right)
{
curSpriteP->destFrameRect.left -= moveBounds.right;
curSpriteP->destFrameRect.right -= moveBounds.right;
}
else if (curSpriteP->destFrameRect.left < moveBounds.left)
{
curSpriteP->destFrameRect.left += moveBounds.right;
curSpriteP->destFrameRect.right += moveBounds.right;
}
// Wrap up or down
if (curSpriteP->destFrameRect.top >= moveBounds.bottom)
{
curSpriteP->destFrameRect.top -= moveBounds.bottom;
curSpriteP->destFrameRect.bottom -= moveBounds.bottom;
}
else if (curSpriteP->destFrameRect.top < moveBounds.top)
{
curSpriteP->destFrameRect.top += moveBounds.bottom;
curSpriteP->destFrameRect.bottom += moveBounds.bottom;
}
curSpriteP = curSpriteP->nextSpriteP;
}
curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
}
// Call the scrolling world move proc
if (spriteWorldP->worldMoveProc != NULL)
{
(*spriteWorldP->worldMoveProc)(spriteWorldP, spriteWorldP->followSpriteP);
}
// Move visScrollRect
if (spriteWorldP->horizScrollDelta || spriteWorldP->vertScrollDelta)
{
SWOffsetCircularVisScrollRect(spriteWorldP,
spriteWorldP->horizScrollDelta,
spriteWorldP->vertScrollDelta);
}
}
// Variables shared by SWAnimateCircularSpriteWorld and SWErasePieceOfSprite.
// These keep track of the vert and horiz scroll rect offset from the previous frame.
short gOldVertScrollRectOffset, gOldHorizScrollRectOffset;
// Variables shared by SWAnimateCircularSpriteWorld and SWDrawTilesInWrappedRect.
// These store the original values of the named variables, so the named variables can
// temporarily be changed and restored.
short gTempHorizScrollRectOffset, gTempVertScrollRectOffset;
short gTempOldVertScrollRectOffset, gTempOldHorizScrollRectOffset;
///--------------------------------------------------------------------------------------
// SWAnimateCircularSpriteWorld
///--------------------------------------------------------------------------------------
SW_FUNC void SWAnimateCircularSpriteWorld(
SpriteWorldPtr spriteWorldP)
{
UpdateRectStructPtr curRectStructP,
nextRectStructP;
register SpriteLayerPtr curSpriteLayerP;
register SpritePtr curSpriteP;
Rect *moveBounds = &spriteWorldP->scrollRectMoveBounds;
Rect rectA, rectB, rectC, rectD, tempDstRect;
Boolean horizClip, vertClip;
SW_ASSERT(spriteWorldP != NULL);
SW_ASSERT(spriteWorldP->backFrameP->isFrameLocked);
SW_ASSERT(spriteWorldP->workFrameP->isFrameLocked);
SW_ASSERT(spriteWorldP->windowFrameP->isFrameLocked);
if (!spriteWorldP->frameHasOccurred)
return;
// Add the deadSpriteLayer if there are any Sprites in it.
if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
{
SWAddSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
}
gOldVertScrollRectOffset = spriteWorldP->backRect.bottom *
(spriteWorldP->oldVisScrollRect.top / spriteWorldP->backRect.bottom);
gOldHorizScrollRectOffset = spriteWorldP->backRect.right *
(spriteWorldP->oldVisScrollRect.left / spriteWorldP->backRect.right);
gTempHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
gTempVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
gTempOldVertScrollRectOffset = gOldVertScrollRectOffset;
gTempOldHorizScrollRectOffset = gOldHorizScrollRectOffset;
// Set the port to the work area so we can draw in it
SetGWorld(spriteWorldP->workFrameP->framePort, nil);
// Update the tiles as we scroll
SWDrawTilesInCircularScrollRect(spriteWorldP);
//-----------------erase the sprites--------------------
rectA = spriteWorldP->oldVisScrollRect;
// Wrap right side to the left
if (rectA.right > moveBounds->right)
{
rectB.top = rectA.top;
rectB.bottom = rectA.bottom;
rectB.left = moveBounds->left;
rectB.right = rectA.right - moveBounds->right;
rectA.right = moveBounds->right;
horizClip = true;
}
else
horizClip = false;
// Wrap bottom side to the top
if (rectA.bottom > moveBounds->bottom)
{
rectC.left = rectA.left;
rectC.right = rectA.right;
rectC.top = moveBounds->top;
rectC.bottom = rectA.bottom - moveBounds->bottom;
rectA.bottom = moveBounds->bottom;
rectB.bottom = moveBounds->bottom;;
vertClip = true;
}
else
vertClip = false;
SWEraseSpritesInRect(spriteWorldP, &rectA);
if (horizClip)
{
gOldHorizScrollRectOffset = 0; // Draw the sprites at the left of the world
SWEraseSpritesInRect(spriteWorldP, &rectB);
gOldHorizScrollRectOffset = gTempOldHorizScrollRectOffset;
}
if (vertClip)
{
gOldVertScrollRectOffset = 0; // Draw the sprites at the top of the world
SWEraseSpritesInRect(spriteWorldP, &rectC);
gOldVertScrollRectOffset = gTempOldVertScrollRectOffset;
}
// Wrap the corner piece
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
gOldVertScrollRectOffset = 0; // Draw the sprites at the top of the world
gOldHorizScrollRectOffset = 0; // Draw the sprites at the left of the world
SWEraseSpritesInRect(spriteWorldP, &rectD);
gOldHorizScrollRectOffset = gTempOldHorizScrollRectOffset;
gOldVertScrollRectOffset = gTempOldVertScrollRectOffset;
}
// update flagged background rects
curRectStructP = spriteWorldP->headUpdateRectP;
while ( curRectStructP != NULL )
{
tempDstRect = curRectStructP->updateRect;
// Make the rect local to the offscreen area
tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
// We're not really erasing a sprite, just copying while wrapping
SWEraseWrappedSprite(spriteWorldP, &tempDstRect);
curRectStructP = curRectStructP->nextRectStructP;
}
// Call the postEraseCallBack
if (spriteWorldP->postEraseCallBack != NULL)
(*spriteWorldP->postEraseCallBack)(spriteWorldP);
//-----------------draw the sprites-------------------
rectA = spriteWorldP->visScrollRect;
// wrap right side to the left
if (rectA.right > moveBounds->right)
{
rectB.top = rectA.top;
rectB.bottom = rectA.bottom;
rectB.left = moveBounds->left;
rectB.right = rectA.right - moveBounds->right;
rectA.right = moveBounds->right;
horizClip = true;
}
else
horizClip = false;
// Wrap bottom side to the top
if (rectA.bottom > moveBounds->bottom)
{
rectC.left = rectA.left;
rectC.right = rectA.right;
rectC.top = moveBounds->top;
rectC.bottom = rectA.bottom - moveBounds->bottom;
rectA.bottom = moveBounds->bottom;
rectB.bottom = moveBounds->bottom;
vertClip = true;
}
else
vertClip = false;
SWDrawSpritesInRect(spriteWorldP, &rectA);
if (horizClip)
{
spriteWorldP->horizScrollRectOffset = 0; // Draw the sprites at the left of the world
SWDrawSpritesInRect(spriteWorldP, &rectB);
spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
}
if (vertClip)
{
spriteWorldP->vertScrollRectOffset = 0; // Draw the sprites at the top of the world
SWDrawSpritesInRect(spriteWorldP, &rectC);
spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
}
// Wrap the corner piece
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
spriteWorldP->horizScrollRectOffset = 0; // Draw the sprites at the left of the world
spriteWorldP->vertScrollRectOffset = 0; // Draw the sprites at the top of the world
SWDrawSpritesInRect(spriteWorldP, &rectD);
spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
}
// Clean up //
curSpriteLayerP = spriteWorldP->headSpriteLayerP;
// iterate through the layers in this world
while (curSpriteLayerP != NULL)
{
curSpriteP = curSpriteLayerP->headSpriteP;
// iterate through the sprites in this layer
while (curSpriteP != NULL)
{
// Set last rect to current rect
curSpriteP->oldFrameRect = curSpriteP->destFrameRect;
curSpriteP->needsToBeDrawn = false;
curSpriteP->needsToBeErased = false;
curSpriteP = curSpriteP->nextSpriteP;
}
curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
}
spriteWorldP->oldVisScrollRect = spriteWorldP->visScrollRect;
// Call the postDrawCallBack
if (spriteWorldP->postDrawCallBack != NULL)
(*spriteWorldP->postDrawCallBack)(spriteWorldP);
//-----------------update the screen--------------------
// Set the port to the window
SetGWorld(spriteWorldP->windowFrameP->framePort, nil);
if (spriteWorldP->usingVBL)
{
spriteWorldP->vblTaskRec.hasVBLFired = false;
while ( !spriteWorldP->vblTaskRec.hasVBLFired )
{}
}
// Copy offscreen area to screen while wrapping
SWWrapWorldToScreen(spriteWorldP);
// dispose of flagged background rects
nextRectStructP = spriteWorldP->headUpdateRectP;
while ( nextRectStructP != NULL )
{
curRectStructP = nextRectStructP;
nextRectStructP = curRectStructP->nextRectStructP;
DisposePtr( (Ptr)curRectStructP );
}
spriteWorldP->headUpdateRectP = NULL;
spriteWorldP->numTilesChanged = 0;
// Remove the deadSpriteLayer if we added it earlier.
if ( spriteWorldP->deadSpriteLayerP->headSpriteP != NULL )
{
SWRemoveSpriteLayer(spriteWorldP, spriteWorldP->deadSpriteLayerP);
}
}
#pragma mark -
///--------------------------------------------------------------------------------------
// SWDrawTilesInCircularScrollRect - called by SWAnimateCircularSpriteWorld to update
// the portion of the visScrollRect that just scrolled into view.
///--------------------------------------------------------------------------------------
void SWDrawTilesInCircularScrollRect(
SpriteWorldPtr spriteWorldP)
{
Rect tempDstRect;
short distA, distB;
short hScrollDelta, vScrollDelta;
// Calculate the scrollDelta of the visScrollRect. Since it maybe have
// wrapped around since the previous frame, we must go through some extra
// hoops to make sure we calculate the delta correctly.
distA = spriteWorldP->visScrollRect.left - spriteWorldP->oldVisScrollRect.left;
if (distA < 0) // if (visScrollRect.left < oldVisScrollRect.left)
distB = distA + spriteWorldP->scrollRectMoveBounds.right;
else
distB = distA - spriteWorldP->scrollRectMoveBounds.right;
if ( SW_ABS(distB) < SW_ABS(distA) )
hScrollDelta = distB;
else
hScrollDelta = distA;
// Do the same for the vScrollDelta...
distA = spriteWorldP->visScrollRect.top - spriteWorldP->oldVisScrollRect.top;
if (distA < 0) // if (visScrollRect.top < oldVisScrollRect.top)
distB = distA + spriteWorldP->scrollRectMoveBounds.bottom;
else
distB = distA - spriteWorldP->scrollRectMoveBounds.bottom;
if ( SW_ABS(distB) < SW_ABS(distA) )
vScrollDelta = distB;
else
vScrollDelta = distA;
// Update tiles as we scroll if tiling is turned on
if (spriteWorldP->tilingIsOn)
{
// VisScrollRect moved horizontally
if (hScrollDelta)
{
// Get rect of new vertical section to update
tempDstRect = spriteWorldP->visScrollRect;
if (hScrollDelta < 0)
tempDstRect.right = tempDstRect.left - hScrollDelta; // Moved left
else
tempDstRect.left = tempDstRect.right - hScrollDelta; // Moved right
SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, true);
// Did VisScrollRect moved diagonally?
if (vScrollDelta)
{
// Get rect of new horizontal section to update
tempDstRect = spriteWorldP->visScrollRect;
if (vScrollDelta < 0)
tempDstRect.bottom = tempDstRect.top - vScrollDelta; // Moved up
else
tempDstRect.top = tempDstRect.bottom - vScrollDelta; // Moved down
// Clip off the part we've already updated
if (hScrollDelta < 0)
tempDstRect.left -= hScrollDelta;
else
tempDstRect.right -= hScrollDelta;
// We pass false here to avoid a bug which occured in the
// tile optimizing code when updating tiles twice in one frame
if (tempDstRect.right > tempDstRect.left)
{
SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, false);
}
}
} // VisScrollRect moved vertically only (not diagonally)
else if (vScrollDelta)
{
// Get rect of new horizontal section to update
tempDstRect = spriteWorldP->visScrollRect;
if (vScrollDelta < 0)
tempDstRect.bottom = tempDstRect.top - vScrollDelta; // Moved up
else
tempDstRect.top = tempDstRect.bottom - vScrollDelta; // Moved down
SWDrawTilesInWrappedRect(spriteWorldP, &tempDstRect, true);
}
}
}
///--------------------------------------------------------------------------------------
// SWDrawTilesInWrappedRect - called by SWDrawTilesInCircularScrollRect. This function
// draws the tiles in the rect, while wrapping the rect around the circular world's
// bounds if it is hanging off the edge of the circular world.
///--------------------------------------------------------------------------------------
void SWDrawTilesInWrappedRect(
SpriteWorldPtr spriteWorldP,
Rect* tempDstRectP,
Boolean optimizingMode)
{
Rect* backRectP = &spriteWorldP->scrollRectMoveBounds;
Rect rectA, rectB, rectC, rectD;
Boolean horizClip, vertClip;
rectA = *tempDstRectP;
// Clip and wrap left or right side
if (rectA.right > backRectP->right)
{
// wrap right side to the left
rectB = rectA;
if (rectB.left < backRectP->right)
rectB.left = backRectP->right;
rectB.left -= backRectP->right;
rectB.right -= backRectP->right;
rectA.right = backRectP->right;
horizClip = true;
}
else
horizClip = false;
if (rectA.bottom > backRectP->bottom)
{
// wrap bottom side to the top
rectC = rectA;
if (rectC.top < backRectP->bottom)
rectC.top = backRectP->bottom;
rectC.top -= backRectP->bottom;
rectC.bottom -= backRectP->bottom;
rectA.bottom = backRectP->bottom;
rectB.bottom = backRectP->bottom;
vertClip = true;
}
else
vertClip = false;
if ( (rectA.bottom > rectA.top) && (rectA.right > rectA.left) )
{
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectA, optimizingMode);
SWWrapRectToWorkArea(spriteWorldP, &rectA);
}
if (horizClip)
{
spriteWorldP->horizScrollRectOffset = 0; // Draw the tiles at the left of the world
if ( (rectB.bottom > rectB.top) && (rectB.right > rectB.left) )
{
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectB, optimizingMode);
SWWrapRectToWorkArea(spriteWorldP, &rectB);
}
spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
}
if (vertClip)
{
spriteWorldP->vertScrollRectOffset = 0; // Draw the tiles at the top of the world
if ( (rectC.bottom > rectC.top) && (rectC.right > rectC.left) )
{
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectC, optimizingMode);
SWWrapRectToWorkArea(spriteWorldP, &rectC);
}
spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
}
// Wrap the corner piece
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
spriteWorldP->horizScrollRectOffset = 0; // Draw the tiles at the left of the world
spriteWorldP->vertScrollRectOffset = 0; // Draw the tiles at the top of the world
if ( (rectD.bottom > rectD.top) && (rectD.right > rectD.left) )
{
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectD, optimizingMode);
SWWrapRectToWorkArea(spriteWorldP, &rectD);
}
spriteWorldP->vertScrollRectOffset = gTempVertScrollRectOffset;
spriteWorldP->horizScrollRectOffset = gTempHorizScrollRectOffset;
}
}
///--------------------------------------------------------------------------------------
// SWEraseSpritesInRect - this is called up to four times by SWAnimateCircularSpriteWorld,
// since that function clips the visScrollRect with the scrollingWorldMoveBounds.
// Whenever that rectangle is clipped, the sprites are erased in each piece. This is
// what allows the sprites to wrap around the world, even when they're half on one side
// of the world and half on another side.
//
// This function also handles the drawing of tiles in the updateRect as we scroll.
///--------------------------------------------------------------------------------------
void SWEraseSpritesInRect(
SpriteWorldPtr spriteWorldP,
Rect* updateRectP)
{
register SpriteLayerPtr curSpriteLayerP;
register SpritePtr curSpriteP;
short curTileLayer;
Rect dstRectA, dstRectB, dstRectC, dstRectD;
short rightClip, bottomClip;
//-----------------erase the sprites--------------------
curSpriteLayerP = spriteWorldP->headSpriteLayerP;
curTileLayer = 0;
// iterate through the layers in this world
while (curSpriteLayerP != NULL)
{
curSpriteP = curSpriteLayerP->headSpriteP;
if (curSpriteLayerP->tileLayer > curTileLayer)
curTileLayer = curSpriteLayerP->tileLayer;
// iterate through the sprites in this layer
while (curSpriteP != NULL)
{
SW_ASSERT(curSpriteP->curFrameP->isFrameLocked);
curSpriteP->tileDepth = curTileLayer;
if (curSpriteP->isVisible)
{
dstRectA = curSpriteP->oldFrameRect;
// Here we clip the sprite with the circular world's right and bottom sides.
// Then we clip each piece with the updateRectP and draw it.
// clip off the bottom
if (dstRectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
bottomClip = dstRectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
dstRectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
}
else
bottomClip = 0;
// clip off the right
if (dstRectA.right > spriteWorldP->scrollRectMoveBounds.right)
{
rightClip = dstRectA.right - spriteWorldP->scrollRectMoveBounds.right;
dstRectA.right = spriteWorldP->scrollRectMoveBounds.right;
}
else
rightClip = 0;
// First erase the main piece of the sprite
SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectA);
if (bottomClip) // Wrap bottom piece to top
{
dstRectB.right = dstRectA.right;
dstRectB.left = dstRectA.left;
dstRectB.top = spriteWorldP->scrollRectMoveBounds.top;
dstRectB.bottom = spriteWorldP->scrollRectMoveBounds.top + bottomClip;
SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectB);
}
if (rightClip) // Wrap right piece to the left
{
dstRectC.top = dstRectA.top;
dstRectC.bottom = dstRectA.bottom;
dstRectC.left = spriteWorldP->scrollRectMoveBounds.left;
dstRectC.right = spriteWorldP->scrollRectMoveBounds.left + rightClip;
SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectC);
}
// If there is a corner piece, wrap it too.
if (rightClip && bottomClip)
{
dstRectD.top = dstRectB.top;
dstRectD.bottom = dstRectB.bottom;
dstRectD.left = dstRectC.left;
dstRectD.right = dstRectC.right;
SWErasePieceOfSprite(spriteWorldP, updateRectP, &dstRectD);
}
}
curSpriteP = curSpriteP->nextSpriteP;
}
curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
}
}
///--------------------------------------------------------------------------------------
// SWDrawSpritesInRect - this is called up to four times by SWAnimateCircularSpriteWorld,
// since that function clips the visScrollRect with the scrollingWorldMoveBounds.
// Whenever that rectangle is clipped, the sprites are drawn in each piece. This is
// what allows the sprites to wrap around the world, even when they're half on one side
// of the world and half on another side.
///--------------------------------------------------------------------------------------
void SWDrawSpritesInRect(
SpriteWorldPtr spriteWorldP,
Rect* updateRectP)
{
register SpriteLayerPtr curSpriteLayerP;
register SpritePtr curSpriteP;
Rect srcRectA, srcRectB, srcRectC, srcRectD;
Rect dstRectA, dstRectB, dstRectC, dstRectD;
short rightClip, bottomClip;
curSpriteLayerP = spriteWorldP->headSpriteLayerP;
// iterate through the layers in this world
while (curSpriteLayerP != NULL)
{
curSpriteP = curSpriteLayerP->headSpriteP;
// iterate through the sprites in this layer
while (curSpriteP != NULL)
{
if (curSpriteP->isVisible)
{
srcRectA = curSpriteP->curFrameP->frameRect;
dstRectA = curSpriteP->destFrameRect;
// Here we clip the sprite with the circular world's bounds. Then
// we clip each piece with the updateRectP and draw it.
// clip off the bottom
if (dstRectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
bottomClip = dstRectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
dstRectA.bottom -= bottomClip;
srcRectA.bottom -= bottomClip;
}
else
bottomClip = 0;
// clip off the right
if (dstRectA.right > spriteWorldP->scrollRectMoveBounds.right)
{
rightClip = dstRectA.right - spriteWorldP->scrollRectMoveBounds.right;
dstRectA.right -= rightClip;
srcRectA.right -= rightClip;
}
else
rightClip = 0;
// First draw the main piece of the sprite
SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP,
&srcRectA, &dstRectA);
// Now we wrap any pieces that are hanging off the border of
// the circular scrolling world. (Which were clipped above.)
if (bottomClip) // Wrap bottom piece to top
{
dstRectB.right = dstRectA.right;
dstRectB.left = dstRectA.left;
dstRectB.top = spriteWorldP->scrollRectMoveBounds.top;
dstRectB.bottom = spriteWorldP->scrollRectMoveBounds.top + bottomClip;
srcRectB = srcRectA;
srcRectB.bottom += bottomClip;
srcRectB.top += SW_RECT_HEIGHT(dstRectA);
SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP,
&srcRectB, &dstRectB);
}
if (rightClip) // Wrap right piece to the left
{
dstRectC.top = dstRectA.top;
dstRectC.bottom = dstRectA.bottom;
dstRectC.left = spriteWorldP->scrollRectMoveBounds.left;
dstRectC.right = spriteWorldP->scrollRectMoveBounds.left + rightClip;
srcRectC = srcRectA;
srcRectC.right += rightClip;
srcRectC.left += SW_RECT_WIDTH(dstRectA);
SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP,
&srcRectC, &dstRectC);
}
// If there is a corner piece, wrap it too.
if (rightClip && bottomClip)
{
dstRectD.top = dstRectB.top;
dstRectD.bottom = dstRectB.bottom;
dstRectD.left = dstRectC.left;
dstRectD.right = dstRectC.right;
srcRectD.top = srcRectB.top;
srcRectD.bottom = srcRectB.bottom;
srcRectD.left = srcRectC.left;
srcRectD.right = srcRectC.right;
SWDrawPieceOfSprite(spriteWorldP, updateRectP, curSpriteP,
&srcRectD, &dstRectD);
}
}
curSpriteP = curSpriteP->nextSpriteP;
}
curSpriteLayerP = curSpriteLayerP->nextSpriteLayerP;
}
}
///--------------------------------------------------------------------------------------
// SWErasePieceOfSprite
///--------------------------------------------------------------------------------------
void SWErasePieceOfSprite(
SpriteWorldPtr spriteWorldP,
Rect* updateRectP,
Rect* dstRectP)
{
Rect dstRect = *dstRectP;
short temp;
// Clip the sprite with this portion of the visScrollRect
if (dstRect.top < updateRectP->top)
dstRect.top = updateRectP->top;
if (dstRect.bottom > updateRectP->bottom)
dstRect.bottom = updateRectP->bottom;
if (dstRect.left < updateRectP->left)
dstRect.left = updateRectP->left;
if (dstRect.right > updateRectP->right)
dstRect.right = updateRectP->right;
// Is the sprite visible in this rect?
if ( (dstRect.right > dstRect.left) && (dstRect.bottom > dstRect.top) )
{
// Make the sprite's rect local to the offscreen area
dstRect.top -= gOldVertScrollRectOffset;
dstRect.bottom -= gOldVertScrollRectOffset;
dstRect.left -= gOldHorizScrollRectOffset;
dstRect.right -= gOldHorizScrollRectOffset;
// align the left edge to long word boundary
dstRect.left &= (spriteWorldP->workFrameP->leftAlignFactor);
// align the right edge to long word boundary
temp = dstRect.right & spriteWorldP->workFrameP->rightAlignFactor;
if (temp != 0)
dstRect.right += (spriteWorldP->workFrameP->rightAlignFactor + 1) - temp;
SWEraseWrappedSprite(spriteWorldP, &dstRect);
}
}
///--------------------------------------------------------------------------------------
// SWDrawPieceOfSprite
///--------------------------------------------------------------------------------------
void SWDrawPieceOfSprite(
SpriteWorldPtr spriteWorldP,
Rect* updateRectP,
SpritePtr curSpriteP,
Rect* srcRectP,
Rect* dstRectP)
{
Rect srcRect = *srcRectP;
Rect dstRect = *dstRectP;
Rect tempDstRect;
// Clip the sprite with this portion of the visScrollRect
if (dstRect.top < updateRectP->top)
{
srcRect.top += updateRectP->top - dstRect.top;
dstRect.top = updateRectP->top;
}
if (dstRect.bottom > updateRectP->bottom)
{
srcRect.bottom += updateRectP->bottom - dstRect.bottom;
dstRect.bottom = updateRectP->bottom;
}
if (dstRect.left < updateRectP->left)
{
srcRect.left += updateRectP->left - dstRect.left;
dstRect.left = updateRectP->left;
}
if (dstRect.right > updateRectP->right)
{
srcRect.right += updateRectP->right - dstRect.right;
dstRect.right = updateRectP->right;
}
// Is the sprite visible in this rect?
if ( (dstRect.right > dstRect.left) && (dstRect.bottom > dstRect.top) )
{
gCurrentSpriteBeingDrawn = curSpriteP;
// Make the sprite's rect local to the offscreen area
tempDstRect = dstRect;
tempDstRect.top -= spriteWorldP->vertScrollRectOffset;
tempDstRect.bottom -= spriteWorldP->vertScrollRectOffset;
tempDstRect.left -= spriteWorldP->horizScrollRectOffset;
tempDstRect.right -= spriteWorldP->horizScrollRectOffset;
SWDrawWrappedSprite(curSpriteP, spriteWorldP->workFrameP, &srcRect, &tempDstRect);
gCurrentSpriteBeingDrawn = NULL;
// Draw tiles above sprite
if (spriteWorldP->tilingIsOn &&
curSpriteP->tileDepth <= spriteWorldP->lastActiveTileLayer)
{
SWDrawTilesAboveSprite(spriteWorldP, &dstRect, curSpriteP->tileDepth);
}
}
}
#pragma mark -
///--------------------------------------------------------------------------------------
// SWMoveCircularVisScrollRect
///--------------------------------------------------------------------------------------
SW_FUNC void SWMoveCircularVisScrollRect(
SpriteWorldPtr spriteWorldP,
short horizPos,
short vertPos)
{
short width, height, moveBoundsWidth, moveBoundsHeight;
height = spriteWorldP->visScrollRect.bottom - spriteWorldP->visScrollRect.top;
width = spriteWorldP->visScrollRect.right - spriteWorldP->visScrollRect.left;
spriteWorldP->visScrollRect.top = vertPos;
spriteWorldP->visScrollRect.bottom = vertPos + height;
spriteWorldP->visScrollRect.left = horizPos;
spriteWorldP->visScrollRect.right = horizPos + width;
moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
// Wrap visScrollRect if it has moved past the circular world's moveBounds
if (spriteWorldP->visScrollRect.top >= spriteWorldP->scrollRectMoveBounds.bottom)
{
spriteWorldP->visScrollRect.top -= moveBoundsHeight;
spriteWorldP->visScrollRect.bottom -= moveBoundsHeight;
}
else if (spriteWorldP->visScrollRect.top < spriteWorldP->scrollRectMoveBounds.top)
{
spriteWorldP->visScrollRect.top += moveBoundsHeight;
spriteWorldP->visScrollRect.bottom += moveBoundsHeight;
}
if (spriteWorldP->visScrollRect.left >= spriteWorldP->scrollRectMoveBounds.right)
{
spriteWorldP->visScrollRect.left -= moveBoundsWidth;
spriteWorldP->visScrollRect.right -= moveBoundsWidth;
}
else if (spriteWorldP->visScrollRect.left < spriteWorldP->scrollRectMoveBounds.left)
{
spriteWorldP->visScrollRect.left += moveBoundsWidth;
spriteWorldP->visScrollRect.right += moveBoundsWidth;
}
SWCalculateOffscreenScrollRect(spriteWorldP);
}
///--------------------------------------------------------------------------------------
// SWOffsetCircularVisScrollRect
///--------------------------------------------------------------------------------------
SW_FUNC void SWOffsetCircularVisScrollRect(
SpriteWorldPtr spriteWorldP,
short horizOffset,
short vertOffset)
{
short moveBoundsWidth, moveBoundsHeight;
spriteWorldP->visScrollRect.top += vertOffset;
spriteWorldP->visScrollRect.bottom += vertOffset;
spriteWorldP->visScrollRect.left += horizOffset;
spriteWorldP->visScrollRect.right += horizOffset;
moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
// Wrap visScrollRect if it has moved past the circular world's moveBounds
if (spriteWorldP->visScrollRect.top >= spriteWorldP->scrollRectMoveBounds.bottom)
{
spriteWorldP->visScrollRect.top -= moveBoundsHeight;
spriteWorldP->visScrollRect.bottom -= moveBoundsHeight;
}
else if (spriteWorldP->visScrollRect.top < spriteWorldP->scrollRectMoveBounds.top)
{
spriteWorldP->visScrollRect.top += moveBoundsHeight;
spriteWorldP->visScrollRect.bottom += moveBoundsHeight;
}
if (spriteWorldP->visScrollRect.left >= spriteWorldP->scrollRectMoveBounds.right)
{
spriteWorldP->visScrollRect.left -= moveBoundsWidth;
spriteWorldP->visScrollRect.right -= moveBoundsWidth;
}
else if (spriteWorldP->visScrollRect.left < spriteWorldP->scrollRectMoveBounds.left)
{
spriteWorldP->visScrollRect.left += moveBoundsWidth;
spriteWorldP->visScrollRect.right += moveBoundsWidth;
}
SWCalculateOffscreenScrollRect(spriteWorldP);
}
///--------------------------------------------------------------------------------------
// SWCollideCircularSpriteLayer - compares wrapped srcSprite with wrapped dstSprite
///--------------------------------------------------------------------------------------
SW_FUNC void SWCollideCircularSpriteLayer(
SpriteWorldPtr spriteWorldP,
SpriteLayerPtr srcSpriteLayerP,
SpriteLayerPtr dstSpriteLayerP)
{
SpritePtr srcSpriteP, nextSrcSpriteP;
SpritePtr dstSpriteP, nextDstSpriteP;
Rect sectRect, srcRect[4], dstRect[4];
Boolean srcRectWrapped[4], dstRectWrapped[4];
short srcNum, dstNum, moveBoundsWidth, moveBoundsHeight;
// Don't check for collisions unless the frame has been processed!
if (!spriteWorldP->frameHasOccurred)
return;
moveBoundsWidth = SW_RECT_WIDTH(spriteWorldP->scrollRectMoveBounds);
moveBoundsHeight = SW_RECT_HEIGHT(spriteWorldP->scrollRectMoveBounds);
srcRectWrapped[0] = true; // These values will always be true
dstRectWrapped[0] = true;
srcSpriteP = srcSpriteLayerP->headSpriteP;
// Cycle through all source Sprites
while (srcSpriteP != NULL)
{
// Skip this sprite if it has no collideProc
if (srcSpriteP->spriteCollideProc == NULL)
{
srcSpriteP = srcSpriteP->nextSpriteP;
continue;
}
dstSpriteP = dstSpriteLayerP->headSpriteP;
nextSrcSpriteP = srcSpriteP->nextSpriteP;
srcRect[0] = srcSpriteP->destFrameRect;
//-----------------------Clip the source sprite-----------------------
// Keeps track of which rects were given values
srcRectWrapped[1] = srcRectWrapped[2] = srcRectWrapped[3] = false;
// Wrap bottom piece to the top //
if (srcRect[0].bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
srcRect[1].top = srcRect[0].top - moveBoundsHeight;
srcRect[1].bottom = srcRect[0].bottom - moveBoundsHeight;
srcRect[1].left = srcRect[0].left;
srcRect[1].right = srcRect[0].right;
srcRectWrapped[1] = true;
}
// Wrap right piece to the left //
if (srcRect[0].right > spriteWorldP->scrollRectMoveBounds.right)
{
srcRect[2].top = srcRect[0].top;
srcRect[2].bottom = srcRect[0].bottom;
srcRect[2].left = srcRect[0].left - moveBoundsWidth;
srcRect[2].right = srcRect[0].right - moveBoundsWidth;
srcRectWrapped[2] = true;
}
// Wrap bottom-right piece to upper left corner //
if (srcRectWrapped[1] && srcRectWrapped[2])
{
srcRect[3].top = srcRect[1].top;
srcRect[3].bottom = srcRect[1].bottom;
srcRect[3].left = srcRect[2].left;
srcRect[3].right = srcRect[2].right;
srcRectWrapped[3] = true;
}
// Cycle through all dest Sprites
while (dstSpriteP != NULL)
{
nextDstSpriteP = dstSpriteP->nextSpriteP;
dstRect[0] = dstSpriteP->destFrameRect;
//-----------------------Clip the dest sprite-----------------------
if (srcSpriteP != dstSpriteP)
{
// Keeps track of which rects were given values
dstRectWrapped[1] = dstRectWrapped[2] = dstRectWrapped[3] = false;
// Wrap bottom piece to the top //
if (dstRect[0].bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
dstRect[1].top = dstRect[0].top - moveBoundsHeight;
dstRect[1].bottom = dstRect[0].bottom - moveBoundsHeight;
dstRect[1].left = dstRect[0].left;
dstRect[1].right = dstRect[0].right;
dstRectWrapped[1] = true;
}
// Wrap right piece to the left //
if (dstRect[0].right > spriteWorldP->scrollRectMoveBounds.right)
{
dstRect[2].top = dstRect[0].top;
dstRect[2].bottom = dstRect[0].bottom;
dstRect[2].left = dstRect[0].left - moveBoundsWidth;
dstRect[2].right = dstRect[0].right - moveBoundsWidth;
dstRectWrapped[2] = true;
}
// Wrap bottom-right piece to upper left corner //
if (dstRectWrapped[1] && dstRectWrapped[2])
{
dstRect[3].top = dstRect[1].top;
dstRect[3].bottom = dstRect[1].bottom;
dstRect[3].left = dstRect[2].left;
dstRect[3].right = dstRect[2].right;
dstRectWrapped[3] = true;
}
// Check for overlapping rects (compare each dstRect with each srcRect)
for (srcNum = 0; srcNum <= 3; srcNum++)
{
if (srcRectWrapped[srcNum] == false)
continue;
for (dstNum = 0; dstNum <= 3; dstNum++)
{
if (dstRectWrapped[dstNum] == false)
continue;
if ( (srcRect[srcNum].top < dstRect[dstNum].bottom) &&
(srcRect[srcNum].bottom > dstRect[dstNum].top) &&
(srcRect[srcNum].left < dstRect[dstNum].right) &&
(srcRect[srcNum].right > dstRect[dstNum].left) )
{
sectRect.left = SW_MAX(srcRect[srcNum].left, dstRect[dstNum].left);
sectRect.top = SW_MAX(srcRect[srcNum].top, dstRect[dstNum].top);
sectRect.right = SW_MIN(srcRect[srcNum].right, dstRect[dstNum].right);
sectRect.bottom = SW_MIN(srcRect[srcNum].bottom, dstRect[dstNum].bottom);
(*srcSpriteP->spriteCollideProc)(srcSpriteP, dstSpriteP, §Rect);
}
}
}
}
dstSpriteP = nextDstSpriteP;
}
srcSpriteP = nextSrcSpriteP;
}
}
///--------------------------------------------------------------------------------------
// SWChangeCircularTileImage - this function simply calls SWUpdateCircularTileOnScreen
///--------------------------------------------------------------------------------------
SW_FUNC void SWChangeCircularTileImage(
SpriteWorldPtr spriteWorldP,
short tileID,
short newImage)
{
// Set the current image
spriteWorldP->curTileImage[tileID] = newImage;
// Update the tile image on screen
SWUpdateCircularTileOnScreen(spriteWorldP, tileID);
}
///--------------------------------------------------------------------------------------
// SWUpdateCircularTileOnScreen - this is actually quite similar to SWDrawCircularTile,
// except that it calls SWUpdateTileOnScreen instead of SWDrawTile.
///--------------------------------------------------------------------------------------
SW_FUNC void SWUpdateCircularTileOnScreen(
SpriteWorldPtr spriteWorldP,
short tileID)
{
short oldHorizScrollRectOffset, oldVertScrollRectOffset;
Rect oldVisScrollRect, rectA, rectB, rectC, rectD;
Boolean horizClip, vertClip;
oldVisScrollRect = spriteWorldP->visScrollRect;
oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
rectA = spriteWorldP->visScrollRect;
// Wrap right side to the left
if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
{
rectB.top = rectA.top;
rectB.bottom = rectA.bottom;
rectB.left = spriteWorldP->scrollRectMoveBounds.left;
rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
rectA.right = spriteWorldP->scrollRectMoveBounds.right;
horizClip = true;
}
else
horizClip = false;
// Wrap bottom side to the top
if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
rectC.left = rectA.left;
rectC.right = rectA.right;
rectC.top = spriteWorldP->scrollRectMoveBounds.top;
rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
vertClip = true;
}
else
vertClip = false;
// Update tiles in rectA
spriteWorldP->visScrollRect = rectA;
SWUpdateTileOnScreen(spriteWorldP, tileID);
// Update tiles in rectB
if (horizClip)
{
spriteWorldP->horizScrollRectOffset = 0; // Draw the tile at the left of the world
spriteWorldP->visScrollRect = rectB;
SWUpdateTileOnScreen(spriteWorldP, tileID);
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Update tiles in rectC
if (vertClip)
{
spriteWorldP->vertScrollRectOffset = 0; // Draw the tile at the top of the world
spriteWorldP->visScrollRect = rectC;
SWUpdateTileOnScreen(spriteWorldP, tileID);
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
}
// Update tiles in rectD (corner piece)
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
spriteWorldP->horizScrollRectOffset = 0; // Draw the sprites at the left of the world
spriteWorldP->vertScrollRectOffset = 0; // Draw the sprites at the top of the world
spriteWorldP->visScrollRect = rectD;
SWUpdateTileOnScreen(spriteWorldP, tileID);
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Restore visScrollRect now that we're done
spriteWorldP->visScrollRect = oldVisScrollRect;
}
///--------------------------------------------------------------------------------------
// SWDrawTilesInCircularBackground
///--------------------------------------------------------------------------------------
SW_FUNC OSErr SWDrawTilesInCircularBackground(
SpriteWorldPtr spriteWorldP)
{
short oldHorizScrollRectOffset, oldVertScrollRectOffset;
Rect oldVisScrollRect, rectA, rectB, rectC, rectD;
Boolean horizClip, vertClip;
GWorldPtr holdGWorld;
GDHandle holdGDH;
GetGWorld( &holdGWorld, &holdGDH );
if ( !spriteWorldP->tilingIsInitialized )
{
SWSetStickyIfError(kTilingNotInitialized);
return kTilingNotInitialized;
}
// Save these values so we can restore them later
oldVisScrollRect = spriteWorldP->visScrollRect;
oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
rectA = spriteWorldP->visScrollRect;
// Wrap right side to the left
if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
{
rectB.top = rectA.top;
rectB.bottom = rectA.bottom;
rectB.left = spriteWorldP->scrollRectMoveBounds.left;
rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
rectA.right = spriteWorldP->scrollRectMoveBounds.right;
horizClip = true;
}
else
horizClip = false;
// Wrap bottom side to the top
if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
rectC.left = rectA.left;
rectC.right = rectA.right;
rectC.top = spriteWorldP->scrollRectMoveBounds.top;
rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
vertClip = true;
}
else
vertClip = false;
// Draw tiles in the main piece
spriteWorldP->visScrollRect = rectA;
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectA, true);
// Draw tile in rectB
if (horizClip)
{
spriteWorldP->horizScrollRectOffset = 0; // Draw the tiles at the left of the world
spriteWorldP->visScrollRect = rectB;
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectB, false);
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Draw tile in rectC
if (vertClip)
{
spriteWorldP->vertScrollRectOffset = 0; // Draw the tiles at the top of the world
spriteWorldP->visScrollRect = rectC;
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectC, false);
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
}
// Draw tile in rectD (corner piece)
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
spriteWorldP->horizScrollRectOffset = 0; // Draw the sprites at the left of the world
spriteWorldP->vertScrollRectOffset = 0; // Draw the sprites at the top of the world
spriteWorldP->visScrollRect = rectD;
(*spriteWorldP->tileRectDrawProc)(spriteWorldP, &rectD, false);
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Restore visScrollRect now that we're done
spriteWorldP->visScrollRect = oldVisScrollRect;
// Restore the original port
SetGWorld( holdGWorld, holdGDH );
return noErr;
}
///--------------------------------------------------------------------------------------
// SWDrawCircularTile
///--------------------------------------------------------------------------------------
SW_FUNC void SWDrawCircularTile(
SpriteWorldPtr spriteWorldP,
short dstTileLayer,
short tileRow,
short tileCol,
short tileID)
{
short oldHorizScrollRectOffset, oldVertScrollRectOffset;
Rect tileRect, oldVisScrollRect, rectA, rectB, rectC, rectD;
Boolean horizClip, vertClip;
// We must have a TileMap installed in the dstTileLayer to draw in it!
if (spriteWorldP->tileLayerArray[dstTileLayer] == NULL)
return;
tileRect.top = tileRow * spriteWorldP->tileHeight;
tileRect.left = tileCol * spriteWorldP->tileWidth;
tileRect.bottom = tileRect.top + spriteWorldP->tileHeight;
tileRect.right = tileRect.left + spriteWorldP->tileWidth;
// Save these values so we can restore them later
oldVisScrollRect = spriteWorldP->visScrollRect;
oldHorizScrollRectOffset = spriteWorldP->horizScrollRectOffset;
oldVertScrollRectOffset = spriteWorldP->vertScrollRectOffset;
rectA = spriteWorldP->visScrollRect;
// Wrap right side to the left
if (rectA.right > spriteWorldP->scrollRectMoveBounds.right)
{
rectB.top = rectA.top;
rectB.bottom = rectA.bottom;
rectB.left = spriteWorldP->scrollRectMoveBounds.left;
rectB.right = rectA.right - spriteWorldP->scrollRectMoveBounds.right;
rectA.right = spriteWorldP->scrollRectMoveBounds.right;
horizClip = true;
}
else
horizClip = false;
// Wrap bottom side to the top
if (rectA.bottom > spriteWorldP->scrollRectMoveBounds.bottom)
{
rectC.left = rectA.left;
rectC.right = rectA.right;
rectC.top = spriteWorldP->scrollRectMoveBounds.top;
rectC.bottom = rectA.bottom - spriteWorldP->scrollRectMoveBounds.bottom;
rectA.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
rectB.bottom = spriteWorldP->scrollRectMoveBounds.bottom;
vertClip = true;
}
else
vertClip = false;
// Draw tile in rectA
if ( SW_RECT_IS_IN_RECT(tileRect, rectA) )
{
spriteWorldP->visScrollRect = rectA;
SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
}
// Draw tile in rectB
if (horizClip)
{
spriteWorldP->horizScrollRectOffset = 0; // Draw the tile at the left of the world
if ( SW_RECT_IS_IN_RECT(tileRect, rectB) )
{
spriteWorldP->visScrollRect = rectB;
SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
}
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Draw tile in rectC
if (vertClip)
{
spriteWorldP->vertScrollRectOffset = 0; // Draw the tile at the top of the world
if ( SW_RECT_IS_IN_RECT(tileRect, rectC) )
{
spriteWorldP->visScrollRect = rectC;
SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
}
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
}
// Draw tile in rectD (corner piece)
if (vertClip && horizClip)
{
rectD.left = rectB.left;
rectD.right = rectB.right;
rectD.top = rectC.top;
rectD.bottom = rectC.bottom;
spriteWorldP->horizScrollRectOffset = 0; // Draw the sprites at the left of the world
spriteWorldP->vertScrollRectOffset = 0; // Draw the sprites at the top of the world
if ( SW_RECT_IS_IN_RECT(tileRect, rectD) )
{
spriteWorldP->visScrollRect = rectD;
SWDrawTile(spriteWorldP, dstTileLayer, tileRow, tileCol, tileID);
}
spriteWorldP->vertScrollRectOffset = oldVertScrollRectOffset;
spriteWorldP->horizScrollRectOffset = oldHorizScrollRectOffset;
}
// Put the new tileID in the TileMap (done in case the tile isn't visible in
// any part of the visScrollRect, in which case SWDrawTile would never be called.)
spriteWorldP->tileLayerArray[dstTileLayer]->tileMap[tileRow][tileCol] = tileID;
// Restore visScrollRect now that we're done
spriteWorldP->visScrollRect = oldVisScrollRect;
}